package com.javaweb.annotation.validate.impl;

import com.javaweb.util.core.StringUtil;

/**
 * 中国统一社会信用代码校验
 * @author tank2140896
 */
public class UsccCodeCheck {
	
	/**
	 * 中国统一社会信用代码校验方法
	 * @param usccCode 中国统一社会信用代码
	 * @return boolean true：校验成功；false：校验失败
	 */
    public static boolean check(String usccCode) {
       	if(StringUtil.isEmpty(usccCode)){
    		return false;
    	}
       	return UsccCodeCheckInner.validate(usccCode);
    }

	/**
	 * 中国统一社会信用代码校验内部实现类
	 * @author tank2140896
	 *
	 */
    static class UsccCodeCheckInner {
    	
    	/**
    	 * 统一社会信用代码长度
    	 */
    	private final static int USCC_LEN = 18;
    	    
    	/**
    	 * 权值
    	 */
	    private final static int[] WEIGHT = {1,3,9,27,19,26,16,17,20,29,25,13,8,24,10,30,28};
    	
    	/**
    	 * 统一社会信用代码校验方法
    	 * @param usccCode 统一社会信用代码
    	 * @return boolean true：校验成功；false：校验失败
    	 */
    	private static boolean validate(String usccCode) {
            if (usccCode.length() != USCC_LEN) {
                return false;
            }
            usccCode = usccCode.toUpperCase();
            //用于计算当前判断的统一社会信用代码位数
            int index = 0;
            //用于存放当前位的统一社会信用代码
            char testc;
            //用于存放代码字符和加权因子乘积之和
            int tempSum = 0;
            int tempNum;
            for (index = 0; index <= 16; index++) {
                testc = usccCode.charAt(index);
                if (index == 0) {
                    if (testc != '1' && testc != '5' && testc != '9' && testc != 'Y') {
                        //System.out.println("统一社会信用代码中登记管理部门代码错误");
                        return false;
                    }
                }
                if (index == 1) {
                    if (testc != '1' && testc != '2' && testc != '3' && testc != '9') {
                        //System.out.println("统一社会信用代码中机构类别代码错误");
                        return false;
                    }
                }
                tempNum = charToNum(testc);
                //验证代码中是否有错误字符
                if (tempNum != -1) {
                    tempSum += WEIGHT[index] * tempNum;
                } else {
                    //System.out.println("统一社会信用代码中出现错误字符");
                    return false;
                }
            }
            tempNum = 31 - tempSum % 31;
            if (tempNum == 31) {
                tempNum = 0;
            }
            //按照GB/T 17710标准对统一社会信用代码前17位计算校验码，并与第18位校验位进行比对
            return charToNum(usccCode.charAt(17)) == tempNum;
    	}
    	
        //按照GB32100-2015标准代码字符集将用于检验的字符变为相应数字
        private static int charToNum(char c) {
            return switch (c) {
                case '0' -> 0;
                case '1' -> 1;
                case '2' -> 2;
                case '3' -> 3;
                case '4' -> 4;
                case '5' -> 5;
                case '6' -> 6;
                case '7' -> 7;
                case '8' -> 8;
                case '9' -> 9;
                case 'A' -> 10;
                case 'B' -> 11;
                case 'C' -> 12;
                case 'D' -> 13;
                case 'E' -> 14;
                case 'F' -> 15;
                case 'G' -> 16;
                case 'H' -> 17;
                case 'J' -> 18;
                case 'K' -> 19;
                case 'L' -> 20;
                case 'M' -> 21;
                case 'N' -> 22;
                case 'P' -> 23;
                case 'Q' -> 24;
                case 'R' -> 25;
                case 'T' -> 26;
                case 'U' -> 27;
                case 'W' -> 28;
                case 'X' -> 29;
                case 'Y' -> 30;
                default -> -1;
            };
        }
    	
    }
    
}
